using System;
using System.Collections.Generic;
using System.Linq;

namespace NopSolutions.NopCommerce.LuceneHelper.Tasks
{
    public abstract class BaseTask<T> : ITask where T : BaseTask<T>
    {
        #region Private

        private readonly int _id;

        #endregion

        #region Constructors

        protected BaseTask(int id)
        {
            _id = id;
        }

        protected BaseTask()
            :this(0)
        {
        }

        #endregion

        #region ITask

        public abstract void DoTask(IndexManager indexManager, SearchManager searchManager, IndexWriterWrapper indexer);
        
        public abstract LuceneIndexType IndexType { get; }

        public abstract bool RebuildIndex { get; }

        public virtual void AddToQueue(IList<ITask> tasks)
        {
            if (!tasks.Contains(this))
            {
                var existing =
                    tasks.Where(x => x.GetType().Equals(typeof(T))).Cast<T>().
                        FirstOrDefault(x => x.Id == Id);
                if (existing != null)
                {
                    existing.UpdateTask(this as T);
                }
                else
                {
                    tasks.Add(this);
                }
            }
        }

        public void DoTask(IndexManager indexManager, SearchManager searchManager)
        {
            var indexer = indexManager.GetIndexWriter(IndexType, RebuildIndex);
            using (indexer)
            {
                DoTask(indexManager, searchManager, indexer);
            }
        }

        #endregion

        #region Equals

        public override bool Equals(object obj)
        {
            if (obj == null) return false;

            if (GetType() != obj.GetType()) return false;

            var properties = ComparableProperties().ToList();

            properties.Add(x => x.Id);

            return properties.All(property => property.Invoke(obj as T).Equals(property.Invoke(this as T)));
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return ComparableProperties().Aggregate(1, (current, property) => (current*397) ^ property.Invoke(this as T).GetHashCode());
            }
        }

        public virtual IEnumerable<Func<T, object>> ComparableProperties()
        {
            return new List<Func<T, object>>();
        }

        #endregion

        #region Properties and Methods

        public int Id
        {
            get { return _id; }
        }

        public virtual void UpdateTask(T newTask)
        {

        }

        #endregion
    }
}
